﻿using Engine.AddinManager;
using Engine.Graphics;
using SharpDX;
using SharpDX.Direct3D11;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Xml;

namespace WorldRacing2
{
    [ExportMetadata("Name", "World Racing 2")]
    [ExportMetadata("Version", 1)]
    [Export(typeof(Engine.AddinManager.IAddin))]
    public class GameDll : Engine.AddinManager.IAddin
    {
        #region Private Fields

        internal static Wr2ShaderArray shaderArray;
        private Engine.Engine engine;

        #endregion Private Fields

        #region Public Constructors

        [ImportingConstructor]
        public GameDll([Import("MainEngine")]Engine.Engine engine)
        {
            this.engine = engine;

            // Load Shaderarray
            GameDll.shaderArray = new Wr2ShaderArray(this.engine, ".\\Shaders\\", engine.Grafic.ShaderManager);
        }

        #endregion Public Constructors

        #region Public Properties

        public Engine.Graphics.IShaderArray ShaderArray
        {
            get
            {
                return shaderArray;
            }
        }

        #endregion Public Properties

        #region Public Methods

        public IMaterial CreateEmptyMaterial(MaterialManager materialManager)
        {
            return new WorldRacing2.Material.Wr2Material(0, 0, 0, EnumMappingMode.material32, materialManager);
        }

        /// <summary>
        /// Creates new standard World Racing 2 vertex.
        /// </summary>
        /// <param name="vertex"></param>
        /// <returns></returns>
        IGameVertex IAddin.CreateGameVertice(Engine.Graphics.VertexStructures.MyOwnVertex.PositionNormalTextured vertex)
        {
            Color4 diffuseColor = new Color4() { Red = 0.4f, Green = 0.4f, Blue = 0.4f, Alpha = 1.0f };
            MyOwnVertex.Wr2Data vertexWr2Data = new MyOwnVertex.Wr2Data();
            vertexWr2Data.UV = vertex.UV;
            vertexWr2Data.DiffuseColor = diffuseColor;
            vertexWr2Data.VertexColor = new Color4(0.0f, 0, 0, 0);

            return vertexWr2Data;
        }

        public VertexBufferBinding CreateVertexBufferBinding(SharpDX.Direct3D11.Buffer vertexBufferWr2Data)
        {
            return new VertexBufferBinding(vertexBufferWr2Data, MyOwnVertex.Wr2Data.SizeInBytes(), 0);
        }

        public string GetGameName()
        {
            return "World Racing 2";
        }

        public int GetSizeOfVertex()
        {
            return MyOwnVertex.Wr2Data.SizeInBytes();
        }

        public Engine.Graphics.IMaterial LoadMaterial(System.IO.BinaryReader br, Engine.Graphics.MaterialManager materialManager)
        {
            WorldRacing2.Material.Wr2Material material = WorldRacing2.Material.Wr2Material.FromStream(br, materialManager);

            //using (StreamWriter sw = new StreamWriter("material.xml"))
            //{
            //    string text = material.ToXml(sw);
            //}
            //using(StreamReader sr = new StreamReader("material.xml"))
            //{
            //    var te = Wr2Material.FromXml(sr);
            //}
            return material;
        }

        public Engine.Graphics.IMaterial LoadMaterialXml(XmlTextReader reader, Engine.Graphics.MaterialManager materialManager)
        {
            var material = WorldRacing2.Material.Wr2Material.FromXmlStream(reader, materialManager);
            return material;
        }

        public List<IGameVertex> LoadVerticesFromStream(int numberOfVertices, BinaryReader vertexReader, int BlockSize, int vertexVersion)
        {
            return LoadVerticesFromStream(null, numberOfVertices, vertexReader, BlockSize, vertexVersion);
        }

        public List<IGameVertex> LoadVerticesFromStream(List<Engine.Graphics.VertexStructures.MyOwnVertex.PositionNormalTextured> engineVertices,
            int numberOfVertices, BinaryReader vertexReader, int BlockSize, int vertexVersion)
        {
            List<IGameVertex> gameVertices = new List<IGameVertex>();

            // Read game vertices
            for (int v = 0; v < numberOfVertices; v++)
            {
                MyOwnVertex.Wr2Data vertexWr2Data = MyOwnVertex.Wr2Data.FromStream(vertexReader, vertexVersion);

                // TODO: Create a option in Modelimporter app to change these data there. (Shadow and diffuse color);
                vertexWr2Data.VertexColor = new Color4()
                {
                    Alpha = 0.0f,// Clear WR2 Shadow
                    Red = vertexWr2Data.VertexColor.Red,
                    Green = vertexWr2Data.VertexColor.Green,
                    Blue = vertexWr2Data.VertexColor.Blue
                };
                vertexWr2Data.DiffuseColor = new Color4()
                {
                    Alpha = 1.0f,
                    Red = 0.4f,
                    Green = 0.4f,
                    Blue = 0.4f
                };

                gameVertices.Add(vertexWr2Data);
            }

            if (engineVertices == null)
            {
                return gameVertices;
            }
            else
            {
                if (engineVertices.Count != numberOfVertices)
                    throw new System.Exception("Number of engine vertices doesn´t match number of gamevertices.");

                for (int i = 0; i < engineVertices.Count; i++)
                {
                    MyOwnVertex.Wr2Data tempVertex = (MyOwnVertex.Wr2Data)gameVertices[i];
                    tempVertex.Tu = engineVertices[i].UV.X;
                    tempVertex.Tv = engineVertices[i].UV.Y;
                    gameVertices[i] = tempVertex;
                }

                return gameVertices;
            }
        }

        public void UpdateVertexBuffer(StandardGraphicBuffers standardGraphicBuffers, IGameVertex[] vertices)
        {
            MyOwnVertex.Wr2Data[] data = new MyOwnVertex.Wr2Data[vertices.Length];

            for (int i = 0; i < vertices.Length; i++)
            {
                data[i] = (MyOwnVertex.Wr2Data)vertices[i];
            }

            standardGraphicBuffers.UpdateVertexBufferGameData<MyOwnVertex.Wr2Data>(data);
        }

        #endregion Public Methods
    }
}